#include "Token.h"
#include "math.h"
Token::Token(void)
: m_iFileID(0)
, m_iLocation(0)
, m_cCategory(0)

{
}

Token::Token( SourceID fileID,SrcLocation addr, tok_punctuator_tag t, const TinyInt punctuator_id )
: m_iFileID(fileID)
, m_iLocation(addr)
, m_cCategory(Token::tok_punctuator)
, m_cSubClass(punctuator_id)
{
}
Token::~Token(void)
{
}
Token::Token(SourceID fileID,SrcLocation addr, tok_keyword_tag t, const TinyInt keyword_id)
: m_iFileID(fileID)
, m_iLocation(addr)
, m_cCategory(Token::tok_keyword)
, m_cSubClass(keyword_id)
{
}
Token::Token(SourceID fileID,SrcLocation addr, tok_identifier_tag t, const char  *const pStrBegin, int iStrLen) 
: m_iFileID(fileID)
, m_iLocation(addr)
, m_cCategory(Token::tok_identifier)
, m_cSubClass(Token::tok_identifier)
{
	m_oDetail.m_oIdentifier.m_iLen=iStrLen;
	m_oDetail.m_oIdentifier.m_iPosStart=static_cast<int>(m_oStrings.size());
	for (int i=0;i<iStrLen;i++) m_oStrings.push_back(pStrBegin[i]);
}
template<int N>
Token::Token(SourceID fileID,SrcLocation addr, tok_identifier_tag t, const char (& strId)[N])
: m_iFileID(fileID)
, m_iLocation(addr)
, m_cCategory(Token::tok_identifier)
, m_cSubClass(Token::tok_identifier)
{
	m_oDetail.m_oIdentifier.m_iLen=N;
	m_oDetail.m_oIdentifier.m_iPosStart=m_oStrings.size();
	for (int i=0;i<N;i++) m_oStrings.push_back(strId[i]);
}
Token::Token(SourceID fileID,SrcLocation addr, tok_constant_tag t, TinyInt constant_type, const char  *const pStrBegin, int iStrLen)
: m_iFileID(fileID)
, m_iLocation(addr)
, m_cCategory(Token::tok_constant)
, m_cSubClass(constant_type)
{
	//search for begin with 0 without x have .
	bool havepoint=0,havex=0;
	for (int i=0;i<iStrLen;i++) {
		if (pStrBegin[i]=='.') havepoint=1;
		if (pStrBegin[i]=='x'||pStrBegin[i]=='X') havex=1;
	}
	if (pStrBegin[0]>='1'&&pStrBegin[0]<='9'||pStrBegin[0]=='.'||pStrBegin[0]=='0'&&havepoint&&havex==0) {
		//case for left picture
		bool found=0;
		for (int i=0;i<iStrLen;i++) if (pStrBegin[i]=='e'||pStrBegin[i]=='E'||pStrBegin[i]=='.') {found =1;break;}
		//search for . or e or E
		if (found==0) {
			//case for left picture down direction
			 unsigned long long tp=0;
			 for (int i=0;i<iStrLen;i++) if (pStrBegin[i]>='0'&&pStrBegin[i]<='9') {
				 tp=tp*10+pStrBegin[i]-'0';
			 }
			 if (constant_type==const_int) m_oDetail.m_oConstant.m_intValue=static_cast<int>(tp);
			 else if (constant_type==const_uint) m_oDetail.m_oConstant.m_uintValue=static_cast<unsigned int>(tp);
			 else if (constant_type==const_lint) m_oDetail.m_oConstant.m_lintValue=static_cast<long int>(tp);
			 else if (constant_type==const_ulint) m_oDetail.m_oConstant.m_ulintValue=static_cast<unsigned long int>(tp);
			 else if (constant_type==const_llint) m_oDetail.m_oConstant.m_llintValue=static_cast<long long>(tp);
			 else if (constant_type==const_ulint) m_oDetail.m_oConstant.m_ulintValue=static_cast<unsigned long>(tp);
			 else if (constant_type==const_ullint) m_oDetail.m_oConstant.m_ullintValue=static_cast<unsigned long long>(tp);
			 else if (constant_type==const_float) m_oDetail.m_oConstant.m_floatValue=static_cast<float>(tp);
			 else if (constant_type==const_double) m_oDetail.m_oConstant.m_doubleValue=static_cast<double>(tp);
			 else if (constant_type==const_char) m_oDetail.m_oConstant.m_charValue=static_cast<char>(tp);
			 else if (constant_type==const_enum) m_oDetail.m_oConstant.m_enumValue=static_cast<int>(tp);
			 return;
		}
		else {
			//case for left pictur right direction
			bool pointfound=0,efound=0;
			int fh=1;
			double res=0,base=0.1;
			double aftere=0;
			//res --> result without e E
			for (int i=0;i<iStrLen;i++) {
				if (pStrBegin[i]>='0'&&pStrBegin[i]<='9') {
					if (pointfound) {
						res+=base*(pStrBegin[i]-'0');
						base/=10;
					}
					else {
						res=res*10+pStrBegin[i]-'0';
					}
				}
				else if (pStrBegin[i]=='.') {
					pointfound=1;
				}
				else if (pStrBegin[i]=='e'||pStrBegin[i]=='E') {
					break;
				}
				else if (pStrBegin[i]=='l'||pStrBegin[i]=='L'||pStrBegin[i]=='f'||pStrBegin[i]=='F') break;
			}
			//calc for the e E case
			for (int i=0;i<iStrLen;i++) {
				if (pStrBegin[i]>='0'&&pStrBegin[i]<='9'&&efound) {
					aftere=aftere*10+pStrBegin[i]-'0';
				}
				else if (pStrBegin[i]=='e'||pStrBegin[i]=='E') {
					efound=1;
				}
				else if (pStrBegin[i]=='-') fh=-1;
			}
			if (efound) {
				aftere*=fh;
				res=res*pow(10.0,aftere);
			}
			if (constant_type==const_int) m_oDetail.m_oConstant.m_intValue=static_cast<int>(res);
			else if (constant_type==const_uint) m_oDetail.m_oConstant.m_uintValue=static_cast<unsigned int>(res);
			else if (constant_type==const_lint) m_oDetail.m_oConstant.m_lintValue=static_cast<long int>(res);
			else if (constant_type==const_ulint) m_oDetail.m_oConstant.m_ulintValue=static_cast<unsigned long>(res);
			else if (constant_type==const_llint) m_oDetail.m_oConstant.m_llintValue=static_cast<long long >(res);
			else if (constant_type==const_ulint) m_oDetail.m_oConstant.m_ulintValue=static_cast<unsigned long>(res);	//////////////////////////////////////////////////////////////////////////
			else if (constant_type==const_ullint) m_oDetail.m_oConstant.m_ullintValue=static_cast<unsigned long long >(res);
			else if (constant_type==const_float) m_oDetail.m_oConstant.m_floatValue=static_cast<float>(res);
			else if (constant_type==const_double) m_oDetail.m_oConstant.m_doubleValue=static_cast<double>(res);
			else if (constant_type==const_char) m_oDetail.m_oConstant.m_charValue=static_cast<char>(res);
			else if (constant_type==const_enum) m_oDetail.m_oConstant.m_enumValue=static_cast<int>(res);
			return;
		}
	}
	else if (pStrBegin[0]=='0') {
		//case for right picture
		if (iStrLen==1) {
			//specia case for 0->98->94
			int res=0;
			if (constant_type==const_int) m_oDetail.m_oConstant.m_intValue=static_cast<int>(res);
			else if (constant_type==const_uint) m_oDetail.m_oConstant.m_uintValue=static_cast<unsigned int>(res);
			else if (constant_type==const_lint) m_oDetail.m_oConstant.m_lintValue=static_cast<long int>(res);
			else if (constant_type==const_ulint) m_oDetail.m_oConstant.m_ulintValue=static_cast<unsigned long >(res);
			else if (constant_type==const_llint) m_oDetail.m_oConstant.m_llintValue=static_cast<long long >(res);
			else if (constant_type==const_ullint) m_oDetail.m_oConstant.m_ullintValue=static_cast<unsigned long long>(res);
			else if (constant_type==const_float) m_oDetail.m_oConstant.m_floatValue=static_cast<float>(res);
			else if (constant_type==const_double) m_oDetail.m_oConstant.m_doubleValue=static_cast<double>(res);
			else if (constant_type==const_char) m_oDetail.m_oConstant.m_charValue=static_cast<char>(res);
			else if (constant_type==const_enum) m_oDetail.m_oConstant.m_enumValue=static_cast<int>(res);
			return;
		}
		//if begin with 0 and without x and have . we deal this case before like 0.3e10
		if (!havex) {
			//case for right picture up direction for oct
			unsigned long long tp=0;
			for (int i=0;i<iStrLen;i++) if (pStrBegin[i]>='0'&&pStrBegin[i]<='9') {
				tp=tp*8+pStrBegin[i]-'0';
			}
			if (constant_type==const_int) m_oDetail.m_oConstant.m_intValue=static_cast<int>(tp);
			else if (constant_type==const_uint) m_oDetail.m_oConstant.m_uintValue=static_cast<unsigned int>(tp);
			else if (constant_type==const_lint) m_oDetail.m_oConstant.m_lintValue=static_cast<long int>(tp);
			else if (constant_type==const_ulint) m_oDetail.m_oConstant.m_ulintValue=static_cast<unsigned long>(tp);
			else if (constant_type==const_llint) m_oDetail.m_oConstant.m_llintValue=static_cast<long long>(tp);
			else if (constant_type==const_ullint) m_oDetail.m_oConstant.m_ullintValue=static_cast<unsigned long long>(tp);
			else if (constant_type==const_float) m_oDetail.m_oConstant.m_floatValue=static_cast<float>(tp);
			else if (constant_type==const_double) m_oDetail.m_oConstant.m_doubleValue=static_cast<double>(tp);
			else if (constant_type==const_char) m_oDetail.m_oConstant.m_charValue=static_cast<char>(tp);
			else if (constant_type==const_enum) m_oDetail.m_oConstant.m_enumValue=static_cast<int>(tp);
			return;
		}
		else {
			//case for right picture right direction for hex
			//same way to do it ,so we just copy the code
			//the only difference 1.begin point but begin with 0 is the same effection (no harm~) 2.base before p 3.deal with a-f A-F
			bool pointfound=0,pfound=0;
			int fh=1;
			double res=0,base=0.0625;
			double aftere=0;
			//res --> result without p P
			for (int i=0;i<iStrLen;i++) {
				if (pStrBegin[i]>='0'&&pStrBegin[i]<='9'||pStrBegin[i]>='a'&&pStrBegin[i]<='f'||pStrBegin[i]>='A'&&pStrBegin[i]<='Z') {
					int det;
					if (pStrBegin[i]>='0'&&pStrBegin[i]<='9') det=pStrBegin[i]-'0';
					else if (pStrBegin[i]>='a'&&pStrBegin[i]<='f') det=pStrBegin[i]-'a'+10;
					else if (pStrBegin[i]>='A'&&pStrBegin[i]<='F') det=pStrBegin[i]-'A'+10;
					if (pointfound) {
						res+=base*det;
						base/=16;
					}
					else {
						res=res*16+det;
					}
				}
				else if (pStrBegin[i]=='.') {
					pointfound=1;
				}
				else if (pStrBegin[i]=='p'||pStrBegin[i]=='P') {
					break;
				}
				else if (pStrBegin[i]=='l'||pStrBegin[i]=='L'||pStrBegin[i]=='f'||pStrBegin[i]=='F') break;
			}
			//calc for the p P case
			for (int i=0;i<iStrLen;i++) {
				if (pStrBegin[i]>='0'&&pStrBegin[i]<='9'&&pfound) {
					aftere=aftere*10+pStrBegin[i]-'0';
				}
				else if (pStrBegin[i]=='p'||pStrBegin[i]=='P') {
					pfound=1;
				}
				else if (pStrBegin[i]=='-') fh=-1;
			}
			if (pfound) {
				aftere*=fh;
				res=res*pow(10.0,aftere);
			}
			if (constant_type==const_int) m_oDetail.m_oConstant.m_intValue=static_cast<int>(res);
			else if (constant_type==const_uint) m_oDetail.m_oConstant.m_uintValue=static_cast<unsigned int>(res);
			else if (constant_type==const_lint) m_oDetail.m_oConstant.m_lintValue=static_cast<long >(res);
			else if (constant_type==const_ulint) m_oDetail.m_oConstant.m_ulintValue=static_cast<unsigned long >(res);
			else if (constant_type==const_llint) m_oDetail.m_oConstant.m_llintValue=static_cast<long long>(res);
			else if (constant_type==const_ulint) m_oDetail.m_oConstant.m_ulintValue=static_cast<unsigned long >(res);	//////////////////////////////////////////////////////////////////////////
			else if (constant_type==const_ullint) m_oDetail.m_oConstant.m_ullintValue=static_cast<unsigned long long >(res);
			else if (constant_type==const_float) m_oDetail.m_oConstant.m_floatValue=static_cast<float >(res);
			else if (constant_type==const_double) m_oDetail.m_oConstant.m_doubleValue=static_cast<double>(res);
			else if (constant_type==const_char) m_oDetail.m_oConstant.m_charValue=static_cast<char>(res);
			else if (constant_type==const_enum) m_oDetail.m_oConstant.m_enumValue=static_cast<int>(res);
			return;
		}
	}
}
template<int N>
Token::Token(SourceID fileID,SrcLocation addr, tok_constant_tag t, TinyInt constant_type, const char (&strConstant)[N]) {
	*this=Token::Token(fileID,addr,t,constant_type,strConstant,N);
}
Token::Token(SourceID fileID,SrcLocation addr, tok_string_literal_tag t, const char  *const pStrBegin, int iStrLen)
: m_iFileID(fileID)
, m_iLocation(addr)
, m_cCategory(Token::tok_string_literal)
, m_cSubClass(Token::tok_string_literal)
{
	int cnt=0;
	m_oDetail.m_oStringLiteral.m_iPosStart=static_cast<int>(m_oStrings.size());
	if (iStrLen<2) return; //just in case
	for (int i=1;i<iStrLen;i++) {
		char now=pStrBegin[i];
		if (now=='"') break;
		else if (now=='\\') {
			char toadd;
			if (pStrBegin[i+1]=='x'||pStrBegin[i+1]=='X') {
				int t1=pStrBegin[i+2],t2=pStrBegin[i+3];
				if (pStrBegin[i+2]>='0'&&pStrBegin[i+2]<='9') t1-='0';
				else if (pStrBegin[i+2]>='a'&&pStrBegin[i+2]<='f') t1-='a'+10;
				else if (pStrBegin[i+2]>='A'&&pStrBegin[i+2]<='F') t1-='A'+10;

				if (pStrBegin[i+3]>='0'&&pStrBegin[i+3]<='9') t2-='0';
				else if (pStrBegin[i+3]>='a'&&pStrBegin[i+3]<='f') t2-='a'+10;
				else if (pStrBegin[i+3]>='A'&&pStrBegin[i+3]<='F') t2-='A'+10;
				toadd=t1*16+t2;
				i+=3;
			}
			else if (pStrBegin[i+1]=='\''||pStrBegin[i+1]=='\"'||pStrBegin[i+1]=='\\'||pStrBegin[i+1]=='\?') {
				toadd=pStrBegin[i+1];
				i++;
			}
			else if (pStrBegin[i+1]=='a') {
				toadd='\a';
				i++;
			}
			else if (pStrBegin[i+1]=='b') {
				toadd='\b';
				i++;
			}
			else if (pStrBegin[i+1]=='f') {
				toadd='\f';
				i++;
			}
			else if (pStrBegin[i+1]=='n') {
				toadd='\n';
				i++;
			}
			else if (pStrBegin[i+1]=='r') {
				toadd='\r';
				i++;
			}
			else if (pStrBegin[i+1]=='t') {
				toadd='\t';
				i++;
			}
			else if (pStrBegin[i+1]=='v') {
				toadd='\v';
				i++;
			}
			else {
				int topass;//how much to add to i
				if (pStrBegin[i+1]>='0'&&pStrBegin[i+1]<='7') {
					//one oct digit found
					toadd=pStrBegin[i+1]-'0';
					topass=1;
					if (pStrBegin[i+2]>='0'&&pStrBegin[i+2]<='7') {
						//two oct digit found
						toadd=toadd*8+pStrBegin[i+2]-'0';
						topass=2;
						if (pStrBegin[i+3]>='0'&&pStrBegin[i+3]<='7') {
							//three oct digit found
							toadd=toadd*8+pStrBegin[i+3]-'0';
							topass=3;
						}
					}
					i+=topass;
				}
				else {
					//zero oct digit found! can't happen but in case
					//don't add char don't add cnt just continue
					continue;
				}
			}
			m_oStrings.push_back(toadd);
			cnt++;
		}
		else {
			cnt++;
			m_oStrings.push_back(now);
		}
	}
	m_oDetail.m_oStringLiteral.m_iLen=cnt;
}
template<int N>
Token::Token(SourceID fileID,SrcLocation addr, tok_string_literal_tag t, const char (&stringLiteral)[N]) {
	*this=Token(fileID,addr,t,stringLiteral,N);
}
Token& Token::operator=(const Token& tok) {
	this->m_oDetail=tok.m_oDetail;
	this->m_cCategory=tok.m_cCategory;
	this->m_cSubClass=tok.m_cSubClass;
	this->m_iFileID=tok.m_iFileID;
	this->m_iLocation=tok.m_iLocation;
	return *this;
}
Token::Token(const Token& tok) {
	*this=tok;
}
std::pair<TinyInt, TinyInt>	Token::getTokenCategory() const {
	return std::make_pair(m_cCategory, m_cSubClass);
}
const Token::TokDetail & Token::getTokenDetail() const {
	return Token::m_oDetail;
}
std::pair<SourceID,SrcLocation> Token::getTokLocation()	const {
	return std::make_pair(m_iFileID,m_iLocation);
}
